﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Sockets;
using System.Reflection.Emit;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

using Newtonsoft.Json.Linq;

using Utils.Http;
using Utils.Weixin.Models;

namespace Utils.Weixin
{
    public class WeChatMini : WeChatService
    {

        public WeChatMini(SecretOptions secretOptions, ICacheStrategy cacheStrategy) : base(secretOptions, cacheStrategy)
        {

        }

        public async Task<PhoneInfo> GetMobile(string code)
        {
            var jtoken = await SendAsync(HttpMethod.Post, "wxa/business/getuserphonenumber", new
            {
                code = code
            });
            return jtoken["phone_info"].ToObject<PhoneInfo>();
        }

        public static string GetEvnVersion(string environmentName) => (environmentName.ToLower()) switch
        {
            "development" => "develop",
            "staging" => "trial",
            "production" => "release",
            _ => "release",
        };

        /// <summary>
        /// 无限小程序码
        /// </summary>
        /// <param name="scene"><![CDATA[最大32个可见字符，只支持数字，大小写英文以及部分特殊字符：!#$&'()*+,/:;=?@-._~，其它字符请自行编码为合法字符（因不支持%，中文无法使用 urlencode 处理，请使用其他编码方式）]]></param>
        /// <param name="page">默认是主页，页面 page，例如 pages/index/index</param>
        /// <returns></returns>
        public async Task<Stream> GetQRCode(string scene, string page = null, string environmentName = "release")
        {
            if (environmentName.IsNullOrEmpty())
            {
                environmentName = "release";
            }
            return await SendStreamAsync(HttpMethod.Post, "wxa/getwxacodeunlimit", new
            {
                env_version = environmentName,
                check_path = false,
                scene,
                page
            });
        }


        /// <summary>
        /// 发送模板消息
        /// </summary>
        /// <param name="openId"></param>
        /// <param name="templateId"></param>
        /// <param name="data"></param>
        /// <param name="page">点击模板卡片后的跳转页面，仅限本小程序内的页面。支持带参数,（示例index?foo=bar）。该字段不填则模板无跳转</param>
        /// <param name="miniprogramState">跳转小程序类型：developer为开发版；trial为体验版；formal为正式版；默认为正式版</param>
        /// <returns></returns>
        public async Task SendSubscribeMessage(string openId, string templateId, string page, object data, string miniprogramState)
        {
            await SendAsync(HttpMethod.Post, "cgi-bin/message/subscribe/send", new
            {
                touser = openId,
                template_id = templateId,
                miniprogram_state = miniprogramState,
                page,
                data = data.ToDictionary().ToDictionary(a => a.Key, a => new { value = a.Value })
            });
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="js_code"></param>
        /// <returns></returns>
        public virtual async Task<Jscode2Session> Jscode2session(string js_code)
        {
            var jtoken = await SendAsync(HttpMethod.Get, "sns/jscode2session", new
            {
                appid = options.AppId,
                secret = options.AppSecret,
                js_code,
                grant_type = "authorization_code"
            }, false);
            return jtoken.ToObject<Jscode2Session>();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="transactionNo">原支付交易对应的微信订单号</param>
        /// <param name="logisticsType">1、实体物流配送采用快递公司进行实体物流配送形式 2、同城配送 3、虚拟商品，虚拟商品，例如话费充值，点卡等，无实体配送形式 4、用户自提</param>
        /// <param name="shippings"></param>
        /// <param name="openId"></param>
        /// <returns></returns>
        public async Task UploadShippingInfo(string transactionNo, int logisticsType, List<ShippingInfo> shippings, string openId)
        {
            try
            {

                await SendAsync(HttpMethod.Post, "wxa/sec/order/upload_shipping_info", new
                {
                    order_key = new
                    {
                        order_number_type = 2,
                        transaction_id = transactionNo
                    },
                    delivery_mode = "UNIFIED_DELIVERY",
                    logistics_type = logisticsType,
                    shipping_list = shippings,
                    upload_time = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"),
                    payer = new { openid = openId }
                });
            }
            catch (ThirdException ex)
            {
                if (ex.Code == "268485184" || ex.Code == "48001")
                {
                    return;
                }
                throw;
            }
        }



    }
}
